<?php

namespace App\Model\Dao;

use App\Model\Enum\RiskRuleCollectionTypeEnum;
use App\Model\Enum\RiskRuleMchRefTypeEnum;
use App\Utils\CustomUtils;
use App\Concern\BaseDao;
use App\Utils\DateUtils;
use Hyperf\Database\Query\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\Arr;
use Laminas\Stdlib\RequestInterface;
use Redis;
use App\Utils\RedisUtils;
use Hyperf\Utils\Codec\Json;

/**
 * RiskRuleCollectionDao
 */
class RiskRuleCollectionDao extends BaseDao {

    /**
     * 表名常量
     * 联表的时候通过XxxDao::TABLE获取
     */
    const TABLE = "risk_rule_collection";

    // 不支持软删除
    protected $softDelete = null;

    const TYPE = [
        1 => '系统',
        2 => '商户风控',
        3 => '通道风控',
        4 => '可疑风控集合',
    ];

    const STATUS = [
        0 => '禁用',
        1 => '生效'
    ];

    public function getTypeList () {
        return $this::TYPE;
    }

    public function getStatusList () {
        return $this::STATUS;
    }

    public function strType ($key, $default = '') {
        return Arr::get($this->getTypeList(), $key, $default);
    }

    public function strStatus ($key, $default = '') {
        return Arr::get($this->getStatusList(), $key, $default);
    }

    /**
     * 父类中通过静态函数获取表名, 因为不能通过静态常量获取, 这个函数是固定写在子类中的
     */
    public static function table (): string {
        return self::TABLE;
    }

    /**
     * 全局风控
     */
    const KEY_RULE_LIST_GLOBAL = "table:rule:list:global";

    /**
     * 商户风控
     */
    const KEY_RULE_LIST_MCH = "table:rule:list:mch";

    /**
     * 通道风控
     */
    const KEY_RULE_LIST_CHANNEL = "table:rule:list:channel";

    /**
     * 可疑风控
     */
    const KEY_RULE_LIST_SUSPICIOUS = "table:rule:list:suspicious";


    /**
     * 排序
     *
     * @param Builder $builder
     * @param array   $params
     *
     * @return Builder|mixed
     */
    protected function _buildOrder (Builder $builder, $params = []) {

        // 通过前端提交的参数排序
        if (Arr::exists($params, "orderBy")) {

            [$prop, $order] = $params["orderBy"];

            if (in_array($order, ["asc", "desc"])) {

                //switch ($prop) {
                //    case "yieldMonth":
                //        $builder->orderBy("main.yieldMonth", $order);
                //        break;
                //    default:
                //        break;
                //}
            }
        }
        else {
            $builder->orderBy('main.type', 'asc');
        }

        // 如果友其他固定的排序需求, 在这里写, 例如按照时间降序
        $builder->orderBy("main.createTime", "desc");

        // 追加父类的排序, 父类按照ID升序, 保证排序结果唯一
        return parent::_buildOrder($builder, $params);
    }

    /**
     * 查询条件
     *
     * @param $params
     *
     * @return Builder
     */
    protected function _buildQueryString ($params) {

        // 本表一律命名为main
        $main = sprintf("%s AS main", self::TABLE);

        // 联表表明获取
        //$country = sprintf("%s AS country", CountryDao::TABLE);

        $builder = DB::table($main);

        // 通过 Arr::exists 来判断是否存在该键, isset不准确
        Arr::exists($params, "collectionName") && $builder->where("main.collectionName", "like", "%{$params['collectionName']}%");
        Arr::exists($params, 'type') && $builder->where('main.type', $params['type']);
        Arr::exists($params, 'status') && $builder->where('main.status', $params['status']);

        return $builder;
    }

    /**
     * 清除缓存:全局风控规则列表
     */
    public function clearGlobalRuleList () {
        $key = self::KEY_RULE_LIST_GLOBAL;
        RedisUtils::redisResource()->del($key);
    }

    /**
     * 全局风控规则列表
     *
     * @return array
     */
    public function readGlobalRuleList () {

        // 读取缓存
        $key = self::KEY_RULE_LIST_GLOBAL;
        $list = RedisUtils::redisResource()->get($key);

        if (!!$list) {
            $list = unserialize($list);
        }
        else {

            $main = sprintf("%s AS main", RiskRuleCollectionDao::TABLE);
            $conn = sprintf("%s AS conn", RiskRuleCollectionConnDao::TABLE);
            $rule = sprintf("%s AS rule", RiskRuleInfoDao::TABLE);

            $builder = DB::table($main);
            $builder->join($conn, 'conn.collectionId', 'main.id');
            $builder->join($rule, 'rule.id', 'conn.ruleId');

            $builder->where('main.type', RiskRuleCollectionTypeEnum::GLOBAL);

            $builder->where('main.status', 1);
            $builder->where('conn.status', 1);
            $builder->where('rule.status', 1);

            $builder->selectRaw(join(',', [
                'rule.*',
                'conn.collectionId',
                'conn.ruleId',
                'main.collectionName',
            ]));

            $builder->orderBy('rule.processType', 'asc');
            $builder->orderBy('rule.id', 'asc');

            $list = $builder->get()->toArray();

            // 写入缓存
            RedisUtils::redisResource()->set($key, serialize($list), DateUtils::getDayRemainSecond());
        }

        return $list;
    }

    /**
     * 清除缓存:商户风控规则列表
     *
     * @param $mchNo
     */
    public function clearMchRuleList ($mchNo) {
        $key = self::KEY_RULE_LIST_MCH . ":{$mchNo}";
        RedisUtils::redisResource()->del($key);
    }

    /**
     * 商户风控规则列表
     *
     * @param string $mchNo 商户号
     *
     * @return array
     */
    public function readMchRuleList ($mchNo) {

        // 读取缓存
        $key = self::KEY_RULE_LIST_MCH . ":{$mchNo}";
        $list = RedisUtils::redisResource()->get($key);

        if (!!$list) {
            $list = unserialize($list);
        }
        else {
            $main       = sprintf("%s AS main", RiskRuleMchRefDao::TABLE);
            $collection = sprintf("%s AS collection", RiskRuleCollectionDao::TABLE);
            $conn       = sprintf("%s AS conn", RiskRuleCollectionConnDao::TABLE);
            $rule       = sprintf("%s AS rule", RiskRuleInfoDao::TABLE);

            $builder = DB::table($main);

            $builder->join($collection, 'collection.id', 'main.collectionId');
            $builder->join($conn, 'conn.collectionId', 'collection.id');
            $builder->join($rule, 'rule.id', 'conn.ruleId');

            $builder->where('main.mchNo', $mchNo);
            $builder->where('main.type', RiskRuleMchRefTypeEnum::NORMAL);
            $builder->where('collection.type', RiskRuleCollectionTypeEnum::MERCHANT);

            $builder->where('main.status', 1);
            $builder->where('collection.status', 1);
            $builder->where('conn.status', 1);
            $builder->where('rule.status', 1);


            $builder->selectRaw(join(',', [
                'rule.*',
                'main.mchNo',
                'collection.collectionName',
                'conn.collectionId',
                'conn.ruleId',
            ]));

            $builder->orderBy('rule.processType', 'asc');
            $builder->orderBy('rule.id', 'asc');

            $list = $builder->get()->toArray();

            // 写入缓存
            RedisUtils::redisResource()->set($key, serialize($list), DateUtils::getDayRemainSecond());
        }

        return $list;
    }

    /**
     * 清除缓存:通道风控规则列表
     * @param $channelNo
     */
    public function clearChannelRuleList ($channelNo) {
        $key = self::KEY_RULE_LIST_CHANNEL . ":{$channelNo}";
        RedisUtils::redisResource()->del($key);
    }

    /**
     * 通道风控规则列表
     *
     * @param string $channelNo 通道编号
     *
     * @return array
     */
    public function readChannelRuleList ($channelNo) {

        // 读取缓存
        $key = self::KEY_RULE_LIST_CHANNEL . ":{$channelNo}";
        $list = RedisUtils::redisResource()->get($key);

        if (!!$list) {
            $list = unserialize($list);
        }
        else {

            $main       = sprintf("%s AS main", ChannelInfoDao::TABLE);
            $collection = sprintf("%s AS collection", RiskRuleCollectionDao::TABLE);
            $conn       = sprintf("%s AS conn", RiskRuleCollectionConnDao::TABLE);
            $rule       = sprintf("%s AS rule", RiskRuleInfoDao::TABLE);

            $builder = DB::table($main);

            $builder->join($collection, 'collection.id', 'main.riskCollectionId');
            $builder->join($conn, 'conn.collectionId', 'collection.id');
            $builder->join($rule, 'rule.id', 'conn.ruleId');

            $builder->where('main.channelNo', $channelNo);
            $builder->where('collection.type', RiskRuleCollectionTypeEnum::CHANNEL);

            $builder->where('main.status', 1);
            $builder->where('collection.status', 1);
            $builder->where('conn.status', 1);
            $builder->where('rule.status', 1);


            $builder->selectRaw(join(',', [
                'rule.*',
                'main.channelNo',
                'collection.collectionName',
                'conn.collectionId',
                'conn.ruleId',
            ]));

            $builder->orderBy('rule.processType', 'asc');
            $builder->orderBy('rule.id', 'asc');

            $list = $builder->get()->toArray();

            // 写入缓存
            RedisUtils::redisResource()->set($key, serialize($list), DateUtils::getDayRemainSecond());
        }

        return $list;
    }

    /**
     * 清除缓存:商户可疑风控规则列表
     *
     * @param $mchNo
     */
    public function clearMchSuspiciousRuleList ($mchNo) {
        $key = self::KEY_RULE_LIST_SUSPICIOUS . ":{$mchNo}";
        RedisUtils::redisResource()->del($key);
    }

    /**
     * 商户可疑风控规则列表
     *
     * @param string $mchNo 通道编号
     *
     * @return array
     */
    public function readMchSuspiciousRuleList ($mchNo) {

        // 读取缓存
        $key = self::KEY_RULE_LIST_SUSPICIOUS . ":{$mchNo}";
        $list = RedisUtils::redisResource()->get($key);

        if (!!$list) {
            $list = unserialize($list);
        }
        else {

            $main       = sprintf("%s AS main", RiskRuleMchRefDao::TABLE);
            $collection = sprintf("%s AS collection", RiskRuleCollectionDao::TABLE);
            $conn       = sprintf("%s AS conn", RiskRuleCollectionConnDao::TABLE);
            $rule       = sprintf("%s AS rule", RiskRuleInfoDao::TABLE);

            $builder = DB::table($main);

            $builder->join($collection, 'collection.id', 'main.collectionId');
            $builder->join($conn, 'conn.collectionId', 'collection.id');
            $builder->join($rule, 'rule.id', 'conn.ruleId');

            $builder->where('main.mchNo', $mchNo);
            $builder->where('main.type', RiskRuleMchRefTypeEnum::SUSPICIOUS);
            $builder->where('collection.type', RiskRuleCollectionTypeEnum::SUSPICIOUS);

            $builder->where('main.status', 1);
            $builder->where('collection.status', 1);
            $builder->where('conn.status', 1);
            $builder->where('rule.status', 1);


            $builder->selectRaw(join(',', [
                'rule.*',
                'main.mchNo',
                'collection.collectionName',
                'conn.collectionId',
                'conn.ruleId',
            ]));

            $builder->orderBy('rule.processType', 'asc');
            $builder->orderBy('rule.id', 'asc');

            $list = $builder->get()->toArray();

            // 写入缓存
            RedisUtils::redisResource()->set($key, serialize($list), DateUtils::getDayRemainSecond());
        }

        return $list;
    }
}
